package com.music.lib.kugou;

import com.lcx.annotation.IOCValue;
import com.lcx.util.CopyFileUtil;
import com.lcx.util.JsonHandler;
import com.lcx.util.StringUtil;
import com.music.error.MusicInfoException;
import com.music.lib.MusicLib;
import com.music.util.HttpClient;
import com.music.util.SnowflakeIdFactory;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 酷狗 2018。9。1 版本的爬虫库
 */
@IOCValue(name="defaultLib")
public class KugouMusicLibImpl implements MusicLib {

    @Override
    public String getLibName() {
        return "酷狗网页版库";
    }

    @Override
    public int getDefaultPageSize() {
        return 30;
    }

    /**
     * 需要传递 音乐名称
     * @param param name (string) / page (int) /pageSize (int)
     * @return
     */
    @Override
    public List<MusicInfo> getMusicInfo(Map<String, Object> param) {
        HttpClient.clearAll();
        String name = (String) param.get("name");
        if(name == null) return null;
        Integer page = (int) param.get("page");
        if(page == null) page = 1;
        Integer pageSize = (int)param.get("pageSize");
        if(pageSize == null) pageSize = 30;
        try {
            name = URLEncoder.encode(name,"UTF-8");
        } catch (UnsupportedEncodingException e) {

        }
        long currTime = System.currentTimeMillis();
        String searchUrl = "http://songsearch.kugou.com/song_search_v2?callback=jQuery"+SnowflakeIdFactory.getNextId()+"_"+(currTime-134)+"&keyword="+name+"&page="+page+"&pagesize="+pageSize+"&userid=-1&clientver=&platform=WebFilter&tag=em&filter=2&iscorrection=1&privilege_filter=0&_="+currTime;
        HttpClient.addHead(HttpClient.HEAD_USER_AGENT,HttpClient.AGENT_CHROME_HEAD);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        String result = null;
        try {
            HttpClient.request(searchUrl,null,bos);
            result = new String(bos.toByteArray(),"UTF-8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(result.substring(0,7).startsWith("jQuery")){
            result = result.substring(result.indexOf("(")+1,result.lastIndexOf(")"));
        }
        Map<String,Object> resultInfo = JsonHandler.parseJson(result);
        List<MusicInfo> listMusics = new ArrayList<>();
        if(Objects.equals(1,resultInfo.get("status")) && resultInfo.get("data") != null){
            Map<String,Object> data = (Map<String, Object>) resultInfo.get("data");
            MusicInfo musicInfo;
            String songName;
            Map<String,Object> otherInfo;
            if(data.get("lists")!=null){
                if(data.get("lists")!=null && !List.class.isAssignableFrom(data.get("lists").getClass())){
                    return listMusics;
                }
                List<Map<String,Object>> lists = (List<Map<String, Object>>) data.get("lists");
                for(Map<String,Object> info:lists){
                    songName = (String) info.get("SongName");
                    songName = clearHtmlTag(songName);
                    musicInfo = new MusicInfo();
                    musicInfo.setName(songName);
                    musicInfo.setType((String) info.get("ExtName"));
                    otherInfo = new HashMap<>(2);
                    otherInfo.put("fileHash",clearHtmlTag((String)info.get("FileHash")));
                    otherInfo.put("albumID",info.get("AlbumID"));
                    otherInfo.put("albumName",clearHtmlTag((String)info.get("AlbumName")));
                    otherInfo.put("author",clearHtmlTag((String)info.get("SingerName")));
                    otherInfo.put("displayName",clearHtmlTag((String)info.get("FileName")));
                    otherInfo.put("totalTime",info.get("Duration"));
                    musicInfo.setOtherInfo(otherInfo);
                    musicInfo.setType("mp3");
                    listMusics.add(musicInfo);
                }
            }
        }
        return listMusics;
    }

    @Override
    public boolean supportSplitPage() {
        return true;
    }

    @Override
    public MusicInfo getDetail(MusicInfo musicInfo) {
        HttpClient.clearAll();
        //lyrics //img //play_url
        long currTime = System.currentTimeMillis();
        Map<String,Object> otherInfo = musicInfo.getOtherInfo();
        if(otherInfo == null) return null;
        String albumId = (String) otherInfo.get("albumID");
        if(albumId == null) return null;
        String fileHash = (String) otherInfo.get("fileHash");
        if(fileHash == null) return null;
        String result = null;
        try {
            //2019-05-27 维护酷狗5月份系统升级
            //参数：
            //r
            //callback √
            //hash √
            //album_id √
            //dfid
            //mid
            //platid = 4
            //_ √
            //cookie:
            //kg_mid
            //Hk_lvt_{xxx}
            //kg_dfid
            //kg_dfid_collect
            //Hm_lpvt_{xxx}
            //kg_mid_temp
            //获取mid相当简单，只需对uuid做md5即可，uuid随意（kugou的js源码是guid，c#等语言的uuid，uuid需要去掉-）
            //dfid需要请求https://userservice.kugou.com/risk/v1/r_register_dev接口获取，请求前先做各种参数校验生成
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            Map<String,Object> param = new LinkedHashMap<>();
            param.put("appid",1014);
            param.put("platid",4);
            param.put("clientver",0);
            param.put("clienttime",System.currentTimeMillis()/0x1e3);
            param.put("signature","");
            param.put("mid", CopyFileUtil.getHash(uuid,"MD5"));
            param.put("uuid",UUID.randomUUID().toString().replaceAll("-",""));
            param.put("userid",0);
            param.put("p.token","");
            StringBuilder builder = new StringBuilder();
            param
                .entrySet()
                .stream()
                .filter(e->!e.getKey().equals("signature"))
                .map(e->e.getValue().toString())
                .sorted(Comparator.naturalOrder())
                .forEach(builder::append);
            builder.insert(0,param.get("appid")).append(param.get("appid"));
            String signature = CopyFileUtil.getHash(builder.toString(),"MD5");
            StringBuilder urlParamBuilder = new StringBuilder();
            boolean isFirst = true;
            for(Map.Entry<String,Object> e:param.entrySet()){
                if (isFirst){
                    isFirst = false;
                }else{
                    urlParamBuilder.append("&");
                }
                urlParamBuilder.append(e.getKey()).append("=").append("signature".equals(e.getKey())?signature:e.getValue());
            }
            HttpClient.addHead("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
            HttpClient.addHead("referer","http://www.kugou.com/");
            HttpClient.setRequestMethod("POST");
            String content = "{\"appCodeName\":\"Mozilla\",\"appName\":\"Netscape\",\"appVersion\":\"5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36\",\"connection\":\"other\",\"doNotTrack\":\"\",\"hardwareConcurrency\":4,\"language\":\"zh-CN\",\"languages\":\"zh-CN,zh\",\"maxTouchPoints\":0,\"mimeTypes\":\"application/pdf,application/x-google-chrome-pdf,application/x-nacl,application/x-pnacl\",\"platform\":\"MacIntel\",\"plugins\":\"Chrome PDF Plugin,Chrome PDF Viewer,Native Client\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36\",\"colorDepth\":24,\"pixelDepth\":24,\"screenResolution\":\"1440x900\",\"timezoneOffset\":-480,\"sessionStorage\":true,\"localStorage\":true,\"indexedDB\":true,\"cookie\":true,\"adBlock\":false,\"devicePixelRatio\":2,\"hasLiedOs\":false,\"hasLiedLanguages\":false,\"hasLiedResolution\":false,\"hasLiedBrowser\":false,\"webglRenderer\":\"Intel(R) Iris(TM) Plus Graphics 640\",\"webglVendor\":\"Intel Inc.\",\"canvas\":\"ad7178387f3ad4d10fcedbccf0a35490\",\"fonts\":\"Andale Mono,Arial,Arial Black,Arial Hebrew,Arial Narrow,Arial Rounded MT Bold,Arial Unicode MS,Comic Sans MS,Courier,Courier New,Geneva,Georgia,Helvetica,Helvetica Neue,Impact,LUCIDA GRANDE,Microsoft Sans Serif,Monaco,Palatino,Tahoma,Times,Times New Roman,Trebuchet MS,Verdana,Wingdings,Wingdings 2,Wingdings 3,American Typewriter,Apple Chancery,Apple Color Emoji,Apple SD Gothic Neo,AVENIR,Ayuthaya,Bangla Sangam MN,Baskerville,Big Caslon,Bodoni 72,Bodoni 72 Oldstyle,Bodoni 72 Smallcaps,Bradley Hand,Brush Script MT,Chalkboard,Chalkboard SE,Chalkduster,Cochin,Copperplate,Didot,Euphemia UCAS,Futura,Geeza Pro,Gill Sans,Gujarati Sangam MN,Gurmukhi MN,Heiti SC,Heiti TC,Hiragino Kaku Gothic ProN,Hiragino Mincho ProN,Hoefler Text,Kailasa,Kannada Sangam MN,Krungthep,Malayalam Sangam MN,Marion,Marker Felt,Nadeem,Noteworthy,OPTIMA,Oriya Sangam MN,OSAKA,Papyrus,Plantagenet Cherokee,Rockwell,Savoye LET,Sinhala Sangam MN,Skia,Snell Roundhand,Tamil Sangam MN,Telugu Sangam MN,Thonburi,Zapfino\",\"dt\":\"2019-05-27\",\"time\":\"2019-05-27 09:15:15\",\"userid\":\"\",\"mid\":\""+param.get("mid")+"\",\"uuid\":\""+param.get("uuid")+"\",\"appid\":\""+param.get("appid")+"\",\"webdriver\":false,\"callPhantom\":false,\"tempKgMid\":\"\",\"referrer\":\"\",\"source\":\"http://www.kugou.com/\",\"audioKey\":\"124.04345808873768\"}";
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            HttpClient.request("https://userservice.kugou.com/risk/v1/r_register_dev?"+urlParamBuilder.toString(),Base64.getEncoder().encodeToString(content.getBytes("UTF-8")),bos);
//
            String dfidObj = new String(bos.toByteArray(),"UTF-8");
            Map<String,Object> dfidMap = JsonHandler.parseJson(dfidObj);
            String dfid = null;
            if (dfidMap.get("data")!=null){
                dfidMap = JsonHandler.parseJson(dfidMap.get("data").toString());
                dfid = (String) dfidMap.get("dfid");
            }

//            https://wwwapi.kugou.com/yy/index.php?r=play/getdata&callback=jQuery191036976861469205313_1558919723585&hash=02DA0DCC7B42ABB0C391D4E88CA51303&album_id=599593&dfid=0Q4Vzx0rrshz09fcrp0EabwE&mid=592a1ce60c4de76d36e75835fb4decd9&platid=4&_=1558919723586
            String requestUrl = "https://wwwapi.kugou.com/yy/index.php?r=play/getdata&callback=jQuery"+SnowflakeIdFactory.getNextId()+"_"+(currTime-123)+"&hash="+fileHash+"&album_id="+albumId+"&dfid="+dfid+"&mid="+param.get("mid")+"&platid=4&_="+currTime;
            bos = new ByteArrayOutputStream();
            HttpClient.addHead(HttpClient.HEAD_USER_AGENT,HttpClient.AGENT_CHROME_HEAD);
            HttpClient.request(requestUrl,null,bos);
            result = new String(bos.toByteArray(),"UTF-8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(result.startsWith("jQuery")){
            result = result.substring(result.indexOf("(")+1,result.lastIndexOf(")"));
        }
        Map<String,Object> resultInfo = JsonHandler.parseJson(result);
        if(Objects.equals(1,resultInfo.get("status")) && resultInfo.get("data") != null){
            Map<String,Object> data = (Map<String, Object>) resultInfo.get("data");
            String lyrics = (String) data.get("lyrics");
            String img = (String) data.get("img");
            String playUrl = (String) data.get("play_url");
            if(StringUtil.isNull(playUrl)){
                throw new MusicInfoException("版权问题无法播放！");
            }
            if(StringUtil.isNotNull(lyrics)){
                lyrics = KuGouLrcClear.clearLrc(lyrics);
                musicInfo.setLrc(lyrics);
            }
            musicInfo.setUrl(playUrl);
            otherInfo.put("img",img);
        }
        return musicInfo;
    }

    private String clearHtmlTag(String str){
        if(str == null) return null;
        return str.replaceAll("<em>","").replaceAll("</em>","");
    }

    public static void main(String[] args) throws  Exception{

        MusicLib musicLib = new KugouMusicLibImpl();
        List<MusicInfo> list = musicLib.getMusicInfo(new HashMap<String,Object>(){
            {
                put("name","左边");
                put("page",1);
                put("pageSize",30);
            }
        });
        MusicInfo musicInfo = musicLib.getDetail(list.get(0));

        System.out.println(musicInfo.getLrc());

    }
}
